home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / DirectInput / ActionMapper / actionmapper.cpp next >
Encoding:
C/C++ Source or Header  |  2001-10-31  |  23.3 KB  |  672 lines

  1. //-----------------------------------------------------------------------------
  2. // File: ActionMapper.cpp
  3. //
  4. // Desc: This is a simple sample to demonstrate how to code using the DInput
  5. //       action mapper feature.
  6. //
  7. //-----------------------------------------------------------------------------
  8. #define STRICT
  9. #include <windows.h>
  10. #include <basetsd.h>
  11. #include <math.h>
  12. #include <stdio.h>
  13. #include <DXErr8.h>
  14. #include <tchar.h>
  15. #include <dinput.h>
  16. #include "DIUtil.h"
  17. #include "DXUtil.h"
  18. #include "resource.h"
  19.  
  20.  
  21.  
  22.  
  23. //-----------------------------------------------------------------------------
  24. // Defines, and constants
  25. //-----------------------------------------------------------------------------
  26. // This GUID must be unique for every game, and the same for 
  27. // every instance of this app.  // {67131584-2938-4857-8A2E-D99DC2C82068}
  28. // The GUID allows DirectInput to remember input settings
  29. GUID g_guidApp = { 0x67131584, 0x2938, 0x4857, { 0x8a, 0x2e, 0xd9, 0x9d, 0xc2, 0xc8, 0x20, 0x68 } };
  30.  
  31.  
  32. // DirectInput action mapper reports events only when buttons/axis change
  33. // so we need to remember the present state of relevant axis/buttons for 
  34. // each DirectInput device.  The CInputDeviceManager will store a 
  35. // pointer for each device that points to this struct
  36. struct InputDeviceState
  37. {
  38.     FLOAT fAxisMoveUD;
  39.     BOOL  bButtonForwardThrust;
  40.     BOOL  bButtonReverseThrust;
  41.  
  42.     FLOAT fAxisRotateLR;
  43.     BOOL  bButtonRotateLeft;
  44.     BOOL  bButtonRotateRight;
  45.  
  46.     BOOL  bButtonFireWeapons;
  47.     BOOL  bButtonEnableShield;
  48. };
  49.  
  50.  
  51. // Struct to store the current input state
  52. struct UserInput
  53. {
  54.     FLOAT fAxisMoveUD;
  55.     FLOAT fAxisRotateLR;
  56.     BOOL  bButtonFireWeapons;
  57.     BOOL  bButtonEnableShield;
  58.  
  59.     BOOL  bDoConfigureInput;
  60.     BOOL  bDoQuitGame;
  61. };
  62.  
  63.  
  64. // Input semantics used by this app
  65. enum INPUT_SEMANTICS
  66. {
  67.     // Gameplay semantics
  68.     INPUT_ROTATE_AXIS_LR=1,  INPUT_MOVE_AXIS_UD,       
  69.     INPUT_FIREWEAPONS,       INPUT_ENABLESHIELD,    
  70.     INPUT_TURNLEFT,          INPUT_TURNRIGHT, 
  71.     INPUT_FORWARDTHRUST,     INPUT_REVERSETHRUST,
  72.     INPUT_DISPLAYGAMEMENU,   INPUT_QUITGAME,
  73. };
  74.  
  75. // Actions used by this app
  76. DIACTION g_rgGameAction[] =
  77. {
  78.     // (C:\Program Files\DirectX\DirectInput\User Maps\*.ini)
  79.     // after changing this, otherwise settings won't reset and will be read 
  80.     // from the out of date ini files 
  81.  
  82.     // Device input (joystick, etc.) that is pre-defined by DInput, according
  83.     // to genre type. The genre for this app is space simulators.
  84.     { INPUT_ROTATE_AXIS_LR,  DIAXIS_SPACESIM_LATERAL,      0, TEXT("Rotate left/right"), },
  85.     { INPUT_MOVE_AXIS_UD,    DIAXIS_SPACESIM_MOVE,         0, TEXT("Move"), },
  86.     { INPUT_FIREWEAPONS,     DIBUTTON_SPACESIM_FIRE,       0, TEXT("Fire weapons"), },
  87.     { INPUT_ENABLESHIELD,    DIBUTTON_SPACESIM_GEAR,       0, TEXT("Enable shield"), },
  88.     { INPUT_DISPLAYGAMEMENU, DIBUTTON_SPACESIM_DISPLAY,    0, TEXT("Configure"), },
  89.  
  90.     // Keyboard input mappings
  91.     { INPUT_TURNLEFT,        DIKEYBOARD_LEFT,    0, TEXT("Turn left"), },
  92.     { INPUT_TURNRIGHT,       DIKEYBOARD_RIGHT,   0, TEXT("Turn right"), },
  93.     { INPUT_FORWARDTHRUST,   DIKEYBOARD_UP,      0, TEXT("Forward thrust"), },
  94.     { INPUT_REVERSETHRUST,   DIKEYBOARD_DOWN,    0, TEXT("Reverse thrust"), },
  95.     { INPUT_FIREWEAPONS,     DIKEYBOARD_F,       0, TEXT("Fire weapons"), },
  96.     { INPUT_ENABLESHIELD,    DIKEYBOARD_S,       0, TEXT("Enable shield"), },
  97.     { INPUT_DISPLAYGAMEMENU, DIKEYBOARD_D,       DIA_APPFIXED, TEXT("Configure"), },
  98.     { INPUT_QUITGAME,        DIKEYBOARD_ESCAPE,  DIA_APPFIXED, TEXT("Quit game"), },
  99. };
  100.  
  101. #define NUMBER_OF_GAMEACTIONS    (sizeof(g_rgGameAction)/sizeof(DIACTION))
  102.  
  103.  
  104.  
  105.  
  106. //-----------------------------------------------------------------------------
  107. // Function prototypes 
  108. //-----------------------------------------------------------------------------
  109. INT_PTR CALLBACK StaticMsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );
  110.  
  111.  
  112.  
  113.  
  114. //-----------------------------------------------------------------------------
  115. // Name: class CMyApplication 
  116. // Desc: Application class.
  117. //-----------------------------------------------------------------------------
  118. class CMyApplication 
  119. {
  120.     TCHAR*                  m_strWindowTitle;       // Title for the app's window
  121.     HWND                    m_hWnd;                 // The main app window
  122.     FLOAT                   m_fTime;                // Current time in seconds
  123.     FLOAT                   m_fElapsedTime;         // Time elapsed since last frame
  124.  
  125.     CInputDeviceManager*    m_pInputDeviceManager;  // DirectInput device manager
  126.     DIACTIONFORMAT          m_diafGame;             // Action format for game play
  127.     UserInput               m_UserInput;            // Struct for storing user input 
  128.  
  129.     FLOAT                   m_fWorldRotX;           // World rotation state X-axis
  130.     FLOAT                   m_fWorldRotY;           // World rotation state Y-axis
  131.  
  132. protected:
  133.     HRESULT OneTimeSceneInit();
  134.     HRESULT Render();
  135.     HRESULT FrameMove();
  136.     HRESULT FinalCleanup();
  137.     HRESULT InitInput( HWND hWnd );
  138.     void    UpdateInput( UserInput* pUserInput );
  139.     void    CleanupDirectInput();
  140.  
  141. public:
  142.     HRESULT Create( HINSTANCE hInstance );
  143.     INT     Run();
  144.     INT_PTR MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
  145.  
  146.     CMyApplication();
  147.  
  148.     HRESULT InputAddDeviceCB( CInputDeviceManager::DeviceInfo* pDeviceInfo, const DIDEVICEINSTANCE* pdidi );
  149.     static HRESULT CALLBACK StaticInputAddDeviceCB( CInputDeviceManager::DeviceInfo* pDeviceInfo, const DIDEVICEINSTANCE* pdidi, LPVOID pParam );   
  150. };
  151.  
  152.  
  153.  
  154.  
  155. //-----------------------------------------------------------------------------
  156. // Global access to the app (needed for the global WndProc())
  157. //-----------------------------------------------------------------------------
  158. CMyApplication*    g_pApp  = NULL;
  159. HINSTANCE          g_hInst = NULL;
  160.  
  161.  
  162.  
  163.  
  164. //-----------------------------------------------------------------------------
  165. // Name: WinMain()
  166. // Desc: Application entry point
  167. //-----------------------------------------------------------------------------
  168. INT WINAPI WinMain( HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow )
  169. {
  170.     CMyApplication app;
  171.  
  172.     g_hInst = hInstance;
  173.  
  174.     if( FAILED( app.Create( hInstance ) ) )
  175.         return 0;
  176.  
  177.     return app.Run();
  178. }
  179.  
  180.  
  181.  
  182.  
  183. //-----------------------------------------------------------------------------
  184. // Name: CMyApplication()
  185. // Desc: Constructor
  186. //-----------------------------------------------------------------------------
  187. CMyApplication::CMyApplication()
  188. {
  189.     g_pApp                      = this;
  190.     m_hWnd                      = NULL;
  191.     m_strWindowTitle            = TEXT( "DirectInput ActionMapper Sample" );
  192.     m_pInputDeviceManager       = NULL;
  193.  
  194.     ZeroMemory( &m_UserInput, sizeof(m_UserInput) );
  195.     m_fWorldRotX                = 0.0f;
  196.     m_fWorldRotY                = 0.0f;
  197. }
  198.  
  199.  
  200.  
  201.  
  202. //-----------------------------------------------------------------------------
  203. // Name: Create()
  204. // Desc: Creates the window
  205. //-----------------------------------------------------------------------------
  206. HRESULT CMyApplication::Create( HINSTANCE hInstance )
  207. {
  208.     // Display the main dialog box.
  209.     CreateDialog( hInstance, MAKEINTRESOURCE(IDD_MAIN), 
  210.                   NULL, StaticMsgProc );
  211.     if( NULL == m_hWnd )
  212.         return E_FAIL;
  213.  
  214.     // Initialize the application timer
  215.     DXUtil_Timer( TIMER_START );
  216.  
  217.     return S_OK;
  218. }
  219.  
  220.  
  221.  
  222.  
  223. //-----------------------------------------------------------------------------
  224. // Name: Run()
  225. // Desc: Handles the message loop and calls FrameMove() and Render() when
  226. //       idle.
  227. //-----------------------------------------------------------------------------
  228. INT CMyApplication::Run()
  229. {
  230.     MSG msg;
  231.  
  232.     // Message loop to run the app
  233.     while( TRUE )
  234.     {
  235.         if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
  236.         {
  237.             // Skip WM_KEYDOWN so they aren't handled by the dialog
  238.             if( msg.message == WM_KEYDOWN )
  239.                 continue;
  240.  
  241.             if( !IsDialogMessage( m_hWnd, &msg ) )  
  242.             {
  243.                 TranslateMessage( &msg );
  244.                 DispatchMessage( &msg );
  245.             }
  246.  
  247.             if( msg.message == WM_QUIT )
  248.             {
  249.                 DestroyWindow( m_hWnd );
  250.                 break;
  251.             }
  252.         }
  253.         else
  254.         {
  255.             // Update the time variables
  256.             m_fTime        = DXUtil_Timer( TIMER_GETAPPTIME );
  257.             m_fElapsedTime = DXUtil_Timer( TIMER_GETELAPSEDTIME );
  258.  
  259.             // This app uses idle time processing for the game loop
  260.             if( FAILED( FrameMove() ) )
  261.                 SendMessage( m_hWnd, WM_DESTROY, 0, 0 );
  262.             if( FAILED( Render() ) ) 
  263.                 SendMessage( m_hWnd, WM_DESTROY, 0, 0 );
  264.  
  265.             Sleep( 20 );
  266.         }
  267.     }
  268.  
  269.     FinalCleanup();
  270.  
  271.     return (INT)msg.wParam;
  272. }
  273.  
  274.  
  275.  
  276.  
  277. //-----------------------------------------------------------------------------
  278. // Name: OneTimeSceneInit()
  279. // Desc: Called during initial app startup, this function performs all the
  280. //       permanent initialization.
  281. //-----------------------------------------------------------------------------
  282. HRESULT CMyApplication::OneTimeSceneInit()
  283. {
  284.     // Initialize DirectInput
  285.     InitInput( m_hWnd );
  286.  
  287.     return S_OK;
  288. }
  289.  
  290.  
  291.  
  292.  
  293. //-----------------------------------------------------------------------------
  294. // Name: StaticInputAddDeviceCB()
  295. // Desc: Static callback helper to call into CMyApplication class
  296. //-----------------------------------------------------------------------------
  297. HRESULT CALLBACK CMyApplication::StaticInputAddDeviceCB( 
  298.                                          CInputDeviceManager::DeviceInfo* pDeviceInfo, 
  299.                                          const DIDEVICEINSTANCE* pdidi, 
  300.                                          LPVOID pParam )
  301. {
  302.     CMyApplication* pApp = (CMyApplication*) pParam;
  303.     return pApp->InputAddDeviceCB( pDeviceInfo, pdidi );
  304. }
  305.  
  306.  
  307.  
  308.  
  309. //-----------------------------------------------------------------------------
  310. // Name: InputAddDeviceCB()
  311. // Desc: Called from CInputDeviceManager whenever a device is added. 
  312. //       Set the dead zone, and creates a new InputDeviceState for each device
  313. //-----------------------------------------------------------------------------
  314. HRESULT CMyApplication::InputAddDeviceCB( CInputDeviceManager::DeviceInfo* pDeviceInfo, 
  315.                                                    const DIDEVICEINSTANCE* pdidi )
  316. {
  317.     // Setup the deadzone 
  318.     DIPROPDWORD dipdw;
  319.     dipdw.diph.dwSize       = sizeof(DIPROPDWORD);
  320.     dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
  321.     dipdw.diph.dwObj        = 0;
  322.     dipdw.diph.dwHow        = DIPH_DEVICE;
  323.     dipdw.dwData            = 500;
  324.     pDeviceInfo->pdidDevice->SetProperty( DIPROP_DEADZONE, &dipdw.diph );
  325.  
  326.     // Create a new InputDeviceState for each device so the 
  327.     // app can record its state 
  328.     InputDeviceState* pNewInputDeviceState = new InputDeviceState;
  329.     if (!pNewInputDeviceState)
  330.         return E_FAIL;
  331.     
  332.     ZeroMemory( pNewInputDeviceState, sizeof(InputDeviceState) );
  333.     pDeviceInfo->pParam = (LPVOID) pNewInputDeviceState;
  334.     return S_OK;
  335. }
  336.  
  337.  
  338.  
  339.  
  340. //-----------------------------------------------------------------------------
  341. // Name: InitInput()
  342. // Desc: Initialize DirectInput objects
  343. //-----------------------------------------------------------------------------
  344. HRESULT CMyApplication::InitInput( HWND hWnd )
  345. {
  346.     HRESULT hr;
  347.  
  348.     // Setup action format for the actual gameplay
  349.     ZeroMemory( &m_diafGame, sizeof(DIACTIONFORMAT) );
  350.     m_diafGame.dwSize          = sizeof(DIACTIONFORMAT);
  351.     m_diafGame.dwActionSize    = sizeof(DIACTION);
  352.     m_diafGame.dwDataSize      = NUMBER_OF_GAMEACTIONS * sizeof(DWORD);
  353.     m_diafGame.guidActionMap   = g_guidApp;
  354.     m_diafGame.dwGenre         = DIVIRTUAL_SPACESIM; 
  355.     m_diafGame.dwNumActions    = NUMBER_OF_GAMEACTIONS;
  356.     m_diafGame.rgoAction       = g_rgGameAction;
  357.     m_diafGame.lAxisMin        = -100;
  358.     m_diafGame.lAxisMax        = 100;
  359.     m_diafGame.dwBufferSize    = 16;
  360.     _tcscpy( m_diafGame.tszActionMap, _T("ActionMapper Sample") );
  361.  
  362.     // Create a new input device manager
  363.     m_pInputDeviceManager = new CInputDeviceManager();
  364.  
  365.     if( FAILED( hr = m_pInputDeviceManager->Create( hWnd, NULL, m_diafGame, 
  366.                                                     StaticInputAddDeviceCB, this ) ) )
  367.         return DXTRACE_ERR_NOMSGBOX( TEXT("m_pInputDeviceManager->Create"), hr );
  368.  
  369.     return S_OK;
  370. }
  371.  
  372.  
  373.  
  374.  
  375. //-----------------------------------------------------------------------------
  376. // Name: FrameMove()
  377. // Desc: Called once per frame, the call is the entry point for animating
  378. //       the scene.
  379. //-----------------------------------------------------------------------------
  380. HRESULT CMyApplication::FrameMove()
  381. {
  382.     // Update user input state
  383.     UpdateInput( &m_UserInput );
  384.  
  385.     // Respond to input
  386.     if( m_UserInput.bDoConfigureInput )
  387.     {
  388.         // One-shot per keypress
  389.         m_UserInput.bDoConfigureInput = FALSE;
  390.  
  391.         // Get access to the list of semantically-mapped input devices
  392.         // to delete all InputDeviceState structs before calling ConfigureDevices()
  393.         CInputDeviceManager::DeviceInfo* pDeviceInfos;
  394.         DWORD dwNumDevices;
  395.         m_pInputDeviceManager->GetDevices( &pDeviceInfos, &dwNumDevices );
  396.  
  397.         for( DWORD i=0; i<dwNumDevices; i++ )
  398.         {
  399.             InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam;
  400.             SAFE_DELETE( pInputDeviceState );
  401.             pDeviceInfos[i].pParam = NULL;
  402.         }
  403.  
  404.         // Configure the devices (with edit capability)
  405.         m_pInputDeviceManager->ConfigureDevices( m_hWnd, NULL, NULL, DICD_EDIT, NULL );
  406.     }
  407.  
  408.     // Update the world state according to user input
  409.     if( m_UserInput.fAxisRotateLR )
  410.         m_fWorldRotY += m_fElapsedTime * m_UserInput.fAxisRotateLR;
  411.  
  412.     if( m_UserInput.fAxisMoveUD )
  413.         m_fWorldRotX += m_fElapsedTime * m_UserInput.fAxisMoveUD;
  414.  
  415.     return S_OK;
  416. }
  417.  
  418.  
  419.  
  420.  
  421. //-----------------------------------------------------------------------------
  422. // Name: UpdateInput()
  423. // Desc: Update the user input.  Called once per frame 
  424. //-----------------------------------------------------------------------------
  425. void CMyApplication::UpdateInput( UserInput* pUserInput )
  426. {
  427.     if( NULL == m_pInputDeviceManager )
  428.         return;
  429.  
  430.     // Get access to the list of semantically-mapped input devices
  431.     CInputDeviceManager::DeviceInfo* pDeviceInfos;
  432.     DWORD dwNumDevices;
  433.     m_pInputDeviceManager->GetDevices( &pDeviceInfos, &dwNumDevices );
  434.  
  435.     // Loop through all devices and check game input
  436.     for( DWORD i=0; i<dwNumDevices; i++ )
  437.     {
  438.         DIDEVICEOBJECTDATA rgdod[10];
  439.         DWORD   dwItems = 10;
  440.         HRESULT hr;
  441.         LPDIRECTINPUTDEVICE8 pdidDevice = pDeviceInfos[i].pdidDevice;
  442.         InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam;
  443.  
  444.         hr = pdidDevice->Acquire();
  445.         hr = pdidDevice->Poll();
  446.         hr = pdidDevice->GetDeviceData( sizeof(DIDEVICEOBJECTDATA),
  447.                                         rgdod, &dwItems, 0 );
  448.         if( FAILED(hr) )
  449.             continue;
  450.  
  451.         // Get the sematics codes for the game menu
  452.         for( DWORD j=0; j<dwItems; j++ )
  453.         {
  454.             BOOL  bButtonState = (rgdod[j].dwData==0x80) ? TRUE : FALSE;
  455.             FLOAT fButtonState = (rgdod[j].dwData==0x80) ? 1.0f : 0.0f;
  456.             FLOAT fAxisState   = (FLOAT)((int)rgdod[j].dwData)/100.0f;
  457.  
  458.             switch( rgdod[j].uAppData )
  459.             {
  460.                 // Handle relative axis data
  461.                 case INPUT_ROTATE_AXIS_LR: 
  462.                     pInputDeviceState->fAxisRotateLR = fAxisState;
  463.                     break;
  464.                 case INPUT_MOVE_AXIS_UD:
  465.                     pInputDeviceState->fAxisMoveUD = -fAxisState;
  466.                     break;
  467.  
  468.                 // Handle buttons separately so the button state data
  469.                 // doesn't overwrite the axis state data, and handle
  470.                 // each button separately so they don't overwrite each other
  471.                 case INPUT_TURNLEFT:        pInputDeviceState->bButtonRotateLeft    = bButtonState; break;
  472.                 case INPUT_TURNRIGHT:       pInputDeviceState->bButtonRotateRight   = bButtonState; break;
  473.                 case INPUT_FORWARDTHRUST:   pInputDeviceState->bButtonForwardThrust = bButtonState; break;
  474.                 case INPUT_REVERSETHRUST:   pInputDeviceState->bButtonReverseThrust = bButtonState; break;
  475.                 case INPUT_FIREWEAPONS:     pInputDeviceState->bButtonFireWeapons   = bButtonState; break;
  476.                 case INPUT_ENABLESHIELD:    pInputDeviceState->bButtonEnableShield  = bButtonState; break;
  477.  
  478.                 // Handle one-shot buttons
  479.                 case INPUT_DISPLAYGAMEMENU: if( bButtonState ) pUserInput->bDoConfigureInput = TRUE; break;
  480.                 case INPUT_QUITGAME:        if( bButtonState ) pUserInput->bDoQuitGame       = TRUE; break;
  481.             }
  482.         }
  483.     }
  484.  
  485.     // Process user input and store result into pUserInput struct
  486.     pUserInput->fAxisRotateLR = 0.0f;
  487.     pUserInput->fAxisMoveUD   = 0.0f;
  488.     pUserInput->bButtonFireWeapons  = FALSE;
  489.     pUserInput->bButtonEnableShield = FALSE;
  490.  
  491.     // Concatinate the data from all the DirectInput devices
  492.     for( i=0; i<dwNumDevices; i++ )
  493.     {
  494.         InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam;
  495.  
  496.         // Use the axis data that is furthest from zero
  497.         if( fabs(pInputDeviceState->fAxisRotateLR) > fabs(pUserInput->fAxisRotateLR) )
  498.             pUserInput->fAxisRotateLR = pInputDeviceState->fAxisRotateLR;
  499.  
  500.         if( fabs(pInputDeviceState->fAxisMoveUD) > fabs(pUserInput->fAxisMoveUD) )
  501.             pUserInput->fAxisMoveUD = pInputDeviceState->fAxisMoveUD;
  502.  
  503.         // Process the button data 
  504.         if( pInputDeviceState->bButtonRotateLeft )
  505.             pUserInput->fAxisRotateLR = -1.0f;
  506.         else if( pInputDeviceState->bButtonRotateRight )
  507.             pUserInput->fAxisRotateLR = 1.0f;
  508.  
  509.         if( pInputDeviceState->bButtonForwardThrust )
  510.             pUserInput->fAxisMoveUD = 1.0f;
  511.         else if( pInputDeviceState->bButtonReverseThrust )
  512.             pUserInput->fAxisMoveUD = -1.0f;
  513.  
  514.         if( pInputDeviceState->bButtonFireWeapons )
  515.             pUserInput->bButtonFireWeapons = TRUE;
  516.         if( pInputDeviceState->bButtonEnableShield )
  517.             pUserInput->bButtonEnableShield = TRUE;
  518.     } 
  519. }
  520.  
  521.  
  522.  
  523.  
  524. //-----------------------------------------------------------------------------
  525. // Name: Render()
  526. // Desc: Called once per frame, the call is the entry point for rendering the 
  527. //       world.
  528. //-----------------------------------------------------------------------------
  529. HRESULT CMyApplication::Render()
  530. {
  531.     TCHAR szMsg[MAX_PATH];
  532.     TCHAR szMsgCurrent[MAX_PATH];
  533.  
  534.     _stprintf( szMsg, TEXT("%0.2f"), m_UserInput.fAxisMoveUD );
  535.     GetWindowText( GetDlgItem(m_hWnd,IDC_UD_AXIS_STATE), szMsgCurrent, MAX_PATH );
  536.     if( lstrcmp( szMsgCurrent, szMsg ) != 0 )
  537.         SetWindowText( GetDlgItem(m_hWnd,IDC_UD_AXIS_STATE), szMsg );
  538.  
  539.     _stprintf( szMsg, TEXT("%0.2f"), m_UserInput.fAxisRotateLR );
  540.     GetWindowText( GetDlgItem(m_hWnd,IDC_LR_AXIS_STATE), szMsgCurrent, MAX_PATH );
  541.     if( lstrcmp( szMsgCurrent, szMsg ) != 0 )
  542.         SetWindowText( GetDlgItem(m_hWnd,IDC_LR_AXIS_STATE), szMsg );
  543.  
  544.     if( !m_UserInput.bButtonEnableShield && !m_UserInput.bButtonFireWeapons )
  545.     {
  546.         _stprintf( szMsg, TEXT("None") );
  547.     }
  548.     else
  549.     {
  550.         _stprintf( szMsg, TEXT("%s%s"), m_UserInput.bButtonEnableShield ? TEXT("Shield ") : TEXT(""), 
  551.                                       m_UserInput.bButtonFireWeapons ? TEXT("Fire ") : TEXT("") );
  552.     }
  553.  
  554.     GetWindowText( GetDlgItem(m_hWnd,IDC_BUTTON_STATE), szMsgCurrent, MAX_PATH );
  555.     if( lstrcmp( szMsgCurrent, szMsg ) != 0 )
  556.         SetWindowText( GetDlgItem(m_hWnd,IDC_BUTTON_STATE), szMsg );
  557.  
  558.     _stprintf( szMsg, TEXT("%0.3f, %0.3f"), m_fWorldRotX, m_fWorldRotY );
  559.     GetWindowText( GetDlgItem(m_hWnd,IDC_WORLD_STATE), szMsgCurrent, MAX_PATH );
  560.     if( lstrcmp( szMsgCurrent, szMsg ) != 0 )
  561.         SetWindowText( GetDlgItem(m_hWnd,IDC_WORLD_STATE), szMsg );
  562.  
  563.     return S_OK;
  564. }
  565.  
  566.  
  567.  
  568.  
  569. //-----------------------------------------------------------------------------
  570. // Name: StaticMsgProc()
  571. // Desc: Static msg handler which passes messages to the application class.
  572. //-----------------------------------------------------------------------------
  573. INT_PTR CALLBACK StaticMsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  574. {
  575.     return g_pApp->MsgProc( hWnd, uMsg, wParam, lParam );
  576. }
  577.  
  578.  
  579.  
  580.  
  581. //-----------------------------------------------------------------------------
  582. // Name: MsgProc()
  583. // Desc: Callback for all Windows messages
  584. //-----------------------------------------------------------------------------
  585. INT_PTR CMyApplication::MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
  586. {
  587.     HRESULT hr;
  588.  
  589.     switch( msg )
  590.     {
  591.         case WM_INITDIALOG:
  592.             m_hWnd = hWnd;
  593.  
  594.             // Initialize the app's custom scene stuff
  595.             if( FAILED( hr = OneTimeSceneInit() ) )
  596.             {
  597.                 DXTRACE_ERR( TEXT("OneTimeSceneInit"), hr );
  598.                 MessageBox( hWnd, TEXT("Error initializing DirectInput.  Sample will now exit."), 
  599.                                   TEXT("DirectInput Sample"), MB_OK | MB_ICONERROR );
  600.                 PostQuitMessage( IDCANCEL );
  601.                 return TRUE;
  602.             }
  603.             break;
  604.  
  605.         case WM_COMMAND:
  606.         {
  607.             switch( LOWORD(wParam) )
  608.             {
  609.                 case IDCANCEL:
  610.                     PostQuitMessage( IDCANCEL );
  611.                     break;
  612.  
  613.                 case IDM_CONFIGINPUT:
  614.                     m_UserInput.bDoConfigureInput = TRUE;
  615.                     break;
  616.             }
  617.             break;
  618.         }
  619.     }
  620.  
  621.     return FALSE;
  622. }
  623.  
  624.  
  625.  
  626.  
  627. //-----------------------------------------------------------------------------
  628. // Name: FinalCleanup()
  629. // Desc: Called before the app exits, this function gives the app the chance
  630. //       to cleanup after itself.
  631. //-----------------------------------------------------------------------------
  632. HRESULT CMyApplication::FinalCleanup()
  633. {
  634.     // Cleanup DirectInput
  635.     CleanupDirectInput();
  636.  
  637.     return S_OK;
  638. }
  639.  
  640.  
  641.  
  642.  
  643. //-----------------------------------------------------------------------------
  644. // Name: CleanupDirectInput()
  645. // Desc: Cleanup DirectInput 
  646. //-----------------------------------------------------------------------------
  647. VOID CMyApplication::CleanupDirectInput()
  648. {
  649.     if( NULL == m_pInputDeviceManager )
  650.         return;
  651.  
  652.     // Get access to the list of semantically-mapped input devices
  653.     // to delete all InputDeviceState structs
  654.     CInputDeviceManager::DeviceInfo* pDeviceInfos;
  655.     DWORD dwNumDevices;
  656.     m_pInputDeviceManager->GetDevices( &pDeviceInfos, &dwNumDevices );
  657.  
  658.     for( DWORD i=0; i<dwNumDevices; i++ )
  659.     {
  660.         InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam;
  661.         SAFE_DELETE( pInputDeviceState );
  662.         pDeviceInfos[i].pParam = NULL;
  663.     }
  664.  
  665.     // Cleanup DirectX input objects
  666.     SAFE_DELETE( m_pInputDeviceManager );
  667. }
  668.  
  669.  
  670.  
  671.  
  672.